package com.fcscs.cservice.dao;

import java.sql.Connection;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import com.fcscs.core.domain.BaseEntity.DBLoc;
import com.fcscs.share.dao.ShareConnectionManager;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.PooledDataSource;

public class GuestConnectionManager extends ShareConnectionManager {

	static Logger LOG = Logger.getLogger(GuestConnectionManager.class);
	
	@Resource(name="sessionFactoryGuest")
	protected SessionFactory sessionFactoryGuest;
	@Resource(name="sessionFactoryGuestRO")
	protected SessionFactory sessionFactoryGuestRO;
	@Resource(name="sessionFactoryGuestReport")
	protected SessionFactory sessionFactoryGuestReport;

	protected ComboPooledDataSource dataSourceGuest;
	protected ComboPooledDataSource roDataSourceGuest;
	protected ComboPooledDataSource reportDataSourceGuest;

	
	protected SimpleJdbcTemplate jdbcTemplateGuest;
	protected SimpleJdbcTemplate jdbcTemplateGuestRO;
	
	

	@Autowired
	GuestConnectionManager(@Qualifier("dataSourceCore") DataSource dataSourceCore,
			@Qualifier("dataSourceCoreRO") DataSource roDataSourceCore,
			@Qualifier("dataSource") DataSource dataSource,
			@Qualifier("dataSourceRO") DataSource roDataSource,
			@Qualifier("dataSourceReport") DataSource reportDataSource,
			@Qualifier("dataSourceMisc") DataSource dataSourceMisc,
			@Qualifier("dataSourceMiscRO") DataSource roDataSourceMisc,
			@Qualifier("dataSourceGuest") DataSource dataSourceGuest,
			@Qualifier("dataSourceGuestRO") DataSource roDataSourceGuest,
			@Qualifier("dataSourceGuestReport") DataSource reportDataSourceGuest) {
		super(dataSourceCore, roDataSourceCore, dataSource, roDataSource, reportDataSource, dataSourceMisc, roDataSourceMisc);
		
		this.dataSourceGuest = (ComboPooledDataSource) dataSourceGuest;
		this.roDataSourceGuest = (ComboPooledDataSource) roDataSourceGuest;
		this.reportDataSourceGuest = (ComboPooledDataSource) reportDataSourceGuest;
		
		this.jdbcTemplateGuest = new SimpleJdbcTemplate(dataSourceGuest);
		this.jdbcTemplateGuestRO = new SimpleJdbcTemplate(roDataSourceGuest);

		addDataSource(this.dataSourceGuest);
		addDataSource(this.roDataSourceGuest);
		addDataSource(this.reportDataSourceGuest);
	
	}

	
	@Override
	public Session getCurrentSession(DBLoc loc) {
		if (loc == DBLoc.GUEST) {
			return getGuestSession();
		}
		return super.getCurrentSession(loc);
	}


	private Session getGuestSession() {
		try {
			if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()&&
					roDataSource.getNumConnectionsDefaultUser() > 0) {
					LOG.debug("-------------------return readOnly:");
					return sessionFactoryGuestRO.getCurrentSession();
			} else if (dataSource.getNumConnectionsDefaultUser() > 0) {
				LOG.debug("-------------------return writable:");
				return sessionFactoryGuest.getCurrentSession();
			}
		} catch (Exception e) {
			LOG.error("Error getting connection from main RW db, can't fall back", e);
		}
		LOG.error("Error getting connection from main RW db");
		throw new RuntimeException("No available session");
	}

	@Override
	protected PooledDataSource getDataSource(DBLoc loc, boolean readOnly) {
		if (loc == DBLoc.GUEST) {
			if (readOnly) {
				return roDataSourceGuest;
			} else {
				return dataSourceGuest;
			}
		}
		return super.getDataSource(loc, readOnly);
	}

	@Override
	protected SessionFactory getSessionFactory(DBLoc loc, boolean readOnly) {
		if (loc == DBLoc.GUEST) {
			if (readOnly) {
				return sessionFactoryGuestRO;
			} else {
				return sessionFactoryGuest;
			}
		}
		return super.getSessionFactory(loc, readOnly);
	}

	@Override
	protected SimpleJdbcTemplate getTemplate(DBLoc loc, boolean readOnly) {
		if (loc == DBLoc.GUEST) {
			if (readOnly) {
				return jdbcTemplateGuestRO;
			} else {
				return jdbcTemplateGuest;
			}
		}
		return super.getTemplate(loc, readOnly);
	}

	public Connection getReportConnection(DBLoc loc) {
		try {
			if (loc == DBLoc.GUEST) {
				PooledDataSource pds = reportDataSourceGuest;
				int i = 0;
				do {
					if (pds.getNumConnectionsDefaultUser() > 0) {
						LOG.debug("-------------------return core report connection:");
						return pds.getConnection();
					}
					Thread.sleep(2000);
				} while (i++ < 3);

			} else {
				return super.getReportConnection(loc);
			}
		} catch (Exception e) {
			LOG.error("Error getting connection from core RO db for report", e);
		}
		throw new RuntimeException("No Connection available");
	}

	public SessionFactory getReportSessionFactory(DBLoc loc) {
		try {
			if (loc == DBLoc.GUEST) {
				return sessionFactoryGuestReport;
			} else {
				return super.getReportSessionFactory(loc);
			}
		} catch (Exception e) {
			LOG.error("Error getting session factory report", e);
		}
		throw new RuntimeException("No Session Facotry available for DBLoc:" + loc);
	}



}
